/*
 * PlayScenarioPanel.cpp
 *
 *  Created on: Oct 24, 2011
 *      Author: gonzalo
 */

#include "PlayScenarioPanel.h"
#include "Bullet.h"
#include "Missile.h"
#include "Explosion.h"
#include "Mina.h"
#include "bonus/Bonus.h"
#include "bonus/BasicShieldBonus.h"
#include "bonus/SuperShieldBonus.h"
#include "bonus/InvisibleBonus.h"
#include "bonus/LaserBonus.h"
#include "bonus/MinaBonus.h"
#include "bonus/MissileBonus.h"
#include "listeners/QuitButtonListener.h"
#include "../../common/utils/GameUtils.h"

#define QUIT_BUTTON_DEFAULT_WIDTH 70
#define QUIT_BUTTON_DEFAULT_HEIGHT 50
#define QUIT_BUTTON_DEFAULT_TEXT "Salir"
#define GAME_OVER_DEFAULT_WAIT 3000
#define CANT_BORDERS 4
#define MAX_ANGLE 360

PlayScenarioPanel::PlayScenarioPanel(int xPos, int yPos, Widget* parent, SpaceBattleInterface* interface, bool esAdmin) :
WidgetMovimientoContainer(xPos, yPos,NULL, parent) {
	getPosition(parcel);
	this->owner = interface->getOwner();
	this->height = interface->getHeight();
	this->width = interface->getWidth();
	this->esAdmin = esAdmin;
	this->ultimoIdAsteroide = -1;
	this->interface = interface;
	this->lblGameover = NULL;

	//Create Quit button

	quitButton = new Button(QUIT_BUTTON_DEFAULT_TEXT, Color::CELESTE,
			QUIT_BUTTON_DEFAULT_WIDTH, QUIT_BUTTON_DEFAULT_HEIGHT, width
					- QUIT_BUTTON_DEFAULT_WIDTH, height-QUIT_BUTTON_DEFAULT_HEIGHT, this, new QuitButtonListener());

	//Read the xml and build the elements
	this->addAsteroides(interface->getAsteroides());

	if (interface->getShip() != NULL) {
		this->addPlayer(interface->getShip());
	}
}

void PlayScenarioPanel::addAsteroides(std::list<Asteroide*> asteroidesList) {
	std::list<Asteroide*>::iterator asteroide;

	Asteroide* aux = NULL;
	for (asteroide = asteroidesList.begin(); asteroide != asteroidesList.end(); ++asteroide) {
		aux = (Asteroide*)*asteroide;

		aux->setParent(this);

		add(aux);
		if(aux->getId() > this->ultimoIdAsteroide){
			this->ultimoIdAsteroide = aux->getId();
		}
	}
}

void PlayScenarioPanel::addPlayer(ShipStatus* shipStatus) {

	//There is bug here apparently
	if (shipStatus == NULL) {
		Logger::debug("PlayScenarioPanel", "addPlayer", "ShipStatus is null!");
		return;
	}

	//Verifico que esta.
	bool found = false;
	bool firstPlayer = true;

	Ship* jugador = NULL;
	std::list<WidgetMovimiento*>::iterator it;
	for (it = widgets.begin(); it != widgets.end(); ++it) {
		if( (*it)->getType() == SHIP ){

			firstPlayer = false;

			jugador = (Ship*)(*it);
			if (jugador->getOwner() == shipStatus->getOwner()) {
				found = true;
				jugador->updateStatus(shipStatus);
			}
		}
	}

	//Si no lo encontre lo agrego a la pantalla
	if (!found) {
		Ship* newShip = NULL;
		DTOShipStatus* dtoShipStatus = shipStatus->transformInDTO();
		resolveOverlaping(dtoShipStatus);
		ShipStatus* newShipStatus = new ShipStatus(dtoShipStatus);
		newShip = new Ship(newShipStatus, this,firstPlayer,this->esAdmin);
		if(esAdmin){
			getInterface()->setDTOMensaje(newShip->getReturnDTO(newShipStatus->getPosX(),newShipStatus->getPosY()));
		}
		delete dtoShipStatus;
		dtoShipStatus = NULL;
		delete newShipStatus;
		newShipStatus = NULL;

		add(newShip);

	}

	if(firstPlayer){
		owner = shipStatus->getOwner();
	}

}


void PlayScenarioPanel::addAmmo(ammoTypeEnum type) {

	Ship* jugador = NULL;
	std::list<WidgetMovimiento*>::iterator it;
	for (it = widgets.begin(); it != widgets.end(); ++it) {
		if ((*it)->getType() != SHIP ){
			continue;
		}

		jugador = (Ship*)*it;
		if (jugador->isShooting()) {
			Ammo* ammo = NULL;
			switch (type) {
				case AMMO_MISSILE:
					ammo= new Missile(jugador->getFrontAmmoX(), jugador->getFrontAmmoY(),this,
							jugador->getBulletAngle(), jugador->getBulletLifeTime());
					break;
				case AMMO_BULLET:
					ammo = new Bullet(jugador->getFrontAmmoX(), jugador->getFrontAmmoY(),this,
							jugador->getBulletAngle(), jugador->getBulletLifeTime());
					break;
				case AMMO_LASER:
					ammo = new Laser(jugador->getFrontAmmoX(), jugador->getFrontAmmoY(),this,
							jugador->getBulletAngle(), jugador->getBulletLifeTime());
					break;
				case AMMO_MINA:
					ammo = new Mina(jugador->getBackAmmoX(), jugador->getBackAmmoY(),this,
							jugador->getBulletAngle(), jugador->getBulletLifeTime(),jugador->duenoesinstancialocal);
					break;
			}
			add(ammo);
		}
	}

}

ShipStatus* PlayScenarioPanel::getShipStatus() {
	Ship* ship = this->getPlayerShip();
	return ship->getShipStatus();
}

Ship* PlayScenarioPanel::getPlayerShip(bool blankShip) {
	static Ship* jugadorRetorno = NULL;
	Ship* jugador = NULL;

	if(jugadorRetorno && !blankShip) return jugadorRetorno;

    std::list<WidgetMovimiento*>::iterator it;
	for (it = widgets.begin(); it != widgets.end(); ++it) {
		if ((*it)->getType() == SHIP ){
			jugador = (Ship*)*it;
			if (jugador->duenoesinstancialocal) {
				jugadorRetorno = jugador;
			}
		}
	}

	//Parche para terminar el static
	if(blankShip)
		jugadorRetorno = NULL;

	return jugadorRetorno;
}


void PlayScenarioPanel::showOn(SDL_Surface* surface) {
	quitButton->showOn(surface);

	WidgetMovimientoContainer::showOn(surface);

	if(lblGameover!=NULL){
		lblGameover->showOn(surface);
	}

	std::list<WidgetMovimiento*>::iterator it1;
	for (it1 = widgets.begin(); it1 != widgets.end(); ++it1) {
		std::list<WidgetMovimiento*>::iterator it2;
		for (it2 = widgets.begin(); it2 != widgets.end(); ++it2) {
			if((*it1)!=(*it2)){
				if( (*it1)->checkCollision(*it2)){
					(*it1)->handleColision(*it2);
					(*it2)->handleColision(*it1);
				}
			}
		}
	}

}

void PlayScenarioPanel::handleEvent(Event event) {
	if(lblGameover==NULL){
		if(event.getEvent()->user.code == Asteroid_Status){
			std::string data = event.getData();
			DTOAsteroide* asteroide = new DTOAsteroide(data, std::string(SERVER_OWN));

			if(asteroide->actionRequired == UPDATE){
  				updateAsteroid(asteroide);
			}else if (asteroide->getDrawable()){
				createAsteroid(asteroide);
			}

		}

		if(event.getEvent()->user.code == New_Explosion){
			std::string data = event.getData();
			DTOExplosion* explosion = new DTOExplosion(data, std::string(SERVER_OWN));
			add(new Explosion(explosion,this));
		}

		if(event.getEvent()->user.code == New_Bonus){
			std::string data = event.getData();
			DTOBonus* dtoBonus = new DTOBonus(data, std::string(SERVER_OWN));

			Bonus* bonus = NULL;
			switch ((BonusType)dtoBonus->type){
				case BASIC_SHIELD:
					bonus = new BasicShieldBonus(dtoBonus->x, dtoBonus->y,this);
					break;
				case SUPER_SHIELD:
					bonus = new SuperShieldBonus(dtoBonus->x, dtoBonus->y,this);
					break;
				case MISSILE:
					bonus = new MissileBonus(dtoBonus->x, dtoBonus->y,this);
					break;
				case MINA:
					bonus = new MinaBonus(dtoBonus->x, dtoBonus->y,this);
					break;
				case LASER:
					bonus = new LaserBonus(dtoBonus->x, dtoBonus->y,this);
					break;
				case INVISIBLE:
					bonus = new InvisibleBonus(dtoBonus->x, dtoBonus->y,this);
					break;
				case BULLET:
					break;
				case COUNT:
					break;
				case USER_INFO:
					break;
			}

			add(bonus);
		}

		WidgetMovimientoContainer::handleEvent(event);
	}
	quitButton->handleEvent(event);
}

void PlayScenarioPanel::resolve() {
	if(lblGameover==NULL){
		//Seteo la busqueda de asteroides
		setElementQuering(ASTEROID);
		WidgetMovimientoContainer::resolve();
		//Verifico que no se haya quedado sin asteroides el juego
		if(!isQueryResult() && isAdmin()){
			//Obtengo los asteroides
			std::list<Asteroide*> listaAsteroides = interface->getAsteroides();
			std::list<Asteroide*>::iterator it;
			//Los agrego al juego
			for (it = listaAsteroides.begin(); it != listaAsteroides.end(); ++it) {
				//Le pongo el parent
				(*it)->setParent(this);
				//Se reposicionan los asteroides para que salgan desde los bordes
				setNewPosWidgetMov(*it);

				//Send the message
				getInterface()->setDTOMensaje((*it)->getDTO(getOwner()));

				widgets.push_back(*it);
			}
		}
	}else{
		if(timer_gameover.get_ticks()>=GAME_OVER_DEFAULT_WAIT){
			SDL_Event event1;
			event1.type = SDL_USEREVENT;
			event1.user.code = UserDisconected;
			SDL_PushEvent(&event1);
		}
	}
	quitButton->resolve();
}

void PlayScenarioPanel::setNewPosWidgetMov(WidgetMovimiento* widgetMov){

	int objectWidth = widgetMov->parcel->width;
	int objectHeight = widgetMov->parcel->height;

	int heightScreen = getHeight();
	int widthScreen = getWidth();

	int newX = 0;
	int newY = 0;
	//Calculo desde que borde voy a sacar el asteroide
	int border = GameUtils::getRandIntValueInRange(CANT_BORDERS);
	//Calculo nuevo angulo
	int newAngle = GameUtils::getRandIntValueInRange(MAX_ANGLE);

	//De acuerdo al bore elegido establezco la nueva posicion del objeto dentro del borde
	switch(border){
	case 0:
		newX -= objectWidth;
		newY -= objectHeight;
		break;
	case 1:
		newX += widthScreen + objectWidth;
		newY -= objectHeight;
		break;
	case 2:
		newX -= objectWidth;
		newY += heightScreen;
		break;
	case 3:
		newX += widthScreen + objectWidth;
		newY += heightScreen + objectHeight;
		break;
	}
	//Actualizo posicion y nuevo angulo
	widgetMov->updateNextPosition(newX, newY);
	widgetMov->updateNextAngle(newAngle);
}


int PlayScenarioPanel::getHeight() const
{
    return height;
}

int PlayScenarioPanel::getWidth() const{
    return width;
}


int PlayScenarioPanel::getUltimoIdAsteroide(){
    return ++ultimoIdAsteroide;
}
int PlayScenarioPanel::getUltimoIdAsteroideConst(){
    return ultimoIdAsteroide;
}

void PlayScenarioPanel::updateAsteroid(DTOAsteroide* asteroid){
	Asteroide* aux = new Asteroide(asteroid);
	aux->setParent(this);
	if(aux->getId() > this->ultimoIdAsteroide){
		this->ultimoIdAsteroide = aux->getId();
	}
	this->asteroidUpdate = aux;
}

void PlayScenarioPanel::createAsteroid(DTOAsteroide* asteroid){
	Asteroide* aux = new Asteroide(asteroid);
	aux->setParent(this);
	add(aux);
	if(aux->getId() > this->ultimoIdAsteroide){
		this->ultimoIdAsteroide = aux->getId();
	}
}

SpaceBattleInterface* PlayScenarioPanel::getInterface(){
	return interface;
}

std::string PlayScenarioPanel::getOwner(){
	return owner;
}

void PlayScenarioPanel::resolveOverlaping(DTOShipStatus* dtoShipStatus){
	GameUtils::resolveOverlaping(widgets,dtoShipStatus,this->width,this->height);
}

void PlayScenarioPanel::gameover(bool lose){
	if(lose){
		lblGameover = new Label(std::string("GAME OVER"),40,this,this->width/2,this->height/2,123,123,123);
	}else{
		lblGameover = new Label(std::string("YOU WIN"),40,this,this->width/2,this->height/2,123,123,123);
	}
	timer_gameover.start();
}

bool PlayScenarioPanel::isAdmin(){
	return esAdmin;
}

PlayScenarioPanel::~PlayScenarioPanel() {
	delete quitButton;
	if (lblGameover!=NULL){
		delete lblGameover;
	}
}

